#激活函数层的实现
import numpy as np

#定义激活函数ReLU层的类，mask为Relu类的实例变量
class Relu:
    def __init__(self):
        self.mask =None

    #正向传播
    def forward(self, x):
        #mask是由True/False构成的NumPy数组，把x的元素中小于等于0的地方保存为True，大于0的地方保存为False
        self.mask = (x <= 0)
        out = x.copy()
        out[self.mask] = 0
        return out

    #后向传播
    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout
        return dx

#测试Relu层
x = np.array([[1.0, -0.5], [-2.0, 3.0]])
print(x)
mask = (x <= 0)
print(mask)
out = x.copy()
out[mask] = 0
print(out)
print(x)

#定义激活函数Sigmoid层的类：正向传播时将输出报讯在实例变量out中，反向传播时使用该变量out进行计算
class Sigmoid:
    def __init__(self):
        self.out = None

    #正向传播
    def forward(self, x):
        out = 1 / (1 + np.exp(-x))
        self.out = out
        return out

    #反向传播
    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out
        return dx

#定义激活函数Affine/Softmax层的类
class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        self.x = None
        self.dW = None
        self.db = None

    #正向传播
    def forward(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b
        return out

    #反向传播
    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)
        return dx

#定义激活函数Softmax-with-Loss层的类
class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None  #损失
        self.y = None  #softmax的输出
        self.y = None  #监督数据（one-hot vector）

    #正向传播
    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        return self.loss

    #反向传播
    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size
        return dx

#定义softmax()函数
def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)  #溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

#定义cross_entropy_error()函数，针对one-hot表示
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size
